package com.aiyige.setup.util;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;

import com.aiyige.MyApp;
import com.aiyige.configs.MyConfig;
import com.aiyige.location.model.LocationData;
import com.aiyige.setup.model.Setup;
import com.aiyige.setup.model.SetupInfo;
import com.aiyige.setup.service.UpdateSetupService;
import com.aiyige.utils.AppUtils;
import com.aiyige.utils.MD5Util;
import com.aiyige.utils.PreferenceUtil;
import com.alibaba.fastjson.JSON;
import com.vondear.rxtools.RxFileTool;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import okhttp3.ResponseBody;
import retrofit2.Response;
import timber.log.Timber;

/**
 * Created by zhuyakun on 2018/1/16.
 */

public class SetupUtil {
    public static final String SETUP_FILE_DIR = MyConfig.AIYIGE_ROOT_DIR + File.separator;
    public static final String SETUP_FILE_PATH = SETUP_FILE_DIR + "setup.json";
    public static final String PREF_KEY_LAST_UPDATE_SETUP_TIMESTAMP = "com.aiyige.pref.setup.PREF_KEY_LAST_UPDATE_CITY_TIMESTAMP";
    private static final String PREF_KEY_VERSION_NAME = "com.aiyige.pref.setup.PREF_KEY_VERSION_NAME";//setup模块专用，不要用在别处
    private static final String PREF_KEY_SETUPINFO = "com.aiyige.pref.setup.PREF_KEY_SETUPINFO";
    private static final String PREF_KEY_SETUPINFO_TIMESTAMP = "com.aiyige.pref.setup.PREF_KEY_SETUPINFO_TIMESTAMP";
    public static final String GROUP_TYPE_COURSE_TYPE = "course_type";//课程类型
    public static final String GROUP_TYPE_MAJOR_COURSE_TYPE = "major_course_type";//课程类别
    public static final String GROUP_TYPE_SUITABLE_PEOPLE = "applicable_people";//适学人群
    public static final String GROUP_TYPE_LEARN_TARGET = "learning_goals";//学习目标
    public static final String GROUP_TYPE_LEARN_AGE = "learning_ages";//学习年龄
    public static final String GROUP_TYPE_CATEGORY = "category";//兴趣分类
    public static final String GROUP_TYPE_CITY = "city";
    public static final String GROUP_TYPE_GUARANTEE = "guarantee_config";//保障类型
    public static final String GROUP_TYPE_SYSTEM_SLIDE = "system_slide";
    public static final String GROUP_TYPE_ADVERTISEMENT = "advertisement";//广告页
    public static final String GROUP_TYPE_TEACHER = "teacher";
    public static final String GROUP_TYPE_OTHER = "others";
    public static final String GROUP_TYPE_INDEX_SLIDE = "index_slide";
    public static final String GROUP_TYPE_STUDY_SLIDE = "study_slide";
    public static final String GROUP_TYPE_APPLE_PAY = "apple_pay";
    public static final String GROUP_TYPE_AVOCATION = "avocation";
    public static final String GROUP_TYPE_CHANNEL = "channel";
    public static final String GROUP_TYPE_APPLY_REFUND_REASON = "apply_refund_reason";
    public static final String GROUP_TYPE_REJECT_REFUND_REASON = "reject_refund_reason";
    public static final String GROUP_TYPE_GLOBAL_TYPE = "global_type";
    public static final String SUB_GROUP_TYPE_MAJOR_COURSE = "major_course";
    public static final String CHANNEL_ALL = "all";
    public static final String CHANNEL_GENERAL = "general";
    public static final String GUARANTEE_CONFIG_MAJOR_COURSE = "guarantee_config_major_course";
    public static final String GUARANTEE_CONFIG_VIDEO_COURSE = "guarantee_config_video_course";

    private static List<Setup> setupList = new LinkedList<>();
    private static List<Setup> courseTypeList = new LinkedList<>();
    private static List<Setup> suitablePeopleList = new LinkedList<>();
    private static List<Setup> learnTargetList = new LinkedList<>();
    private static List<Setup> categoryList = new LinkedList<>();
    private static List<Setup> cityList = new LinkedList<>();
    private static List<Setup> guaranteeList = new LinkedList<>();
    private static List<Setup> systemSlideList = new LinkedList<>();
    private static List<Setup> advertisementList = new LinkedList<>();

    private static Lock mutex = new ReentrantLock();
    private static Lock copyMutex = new ReentrantLock();
    private static Lock setupInfoMutex = new ReentrantLock();
    public static final long UPDATE_SETUP_INTERVAL_MS = 24 * 60 * 60 * 1000;
    public static final long RANDOM_DELAY_LOW_BOUND_MS = 5 * 60 * 1000;
    public static final long RANDOM_DELAY_RANGE_MS = 5 * 6 * 1000;
    public static final long SETUPINFO_TIMEOUT_MS = 60 * 60 * 1000;

    public static List<Setup> getSetupList() {
        List<Setup> list;
        mutex.lock();
        list = setupList;
        mutex.unlock();
        return list;
    }

    public static List<Setup> getSetupListByGroupType(String groupType) {
        List<Setup> list;
        mutex.lock();
        switch (groupType) {
            case GROUP_TYPE_COURSE_TYPE: {
                list = courseTypeList;
                break;
            }
            case GROUP_TYPE_SUITABLE_PEOPLE: {
                list = suitablePeopleList;
                break;
            }
            case GROUP_TYPE_LEARN_TARGET: {
                list = learnTargetList;
                break;
            }
            case GROUP_TYPE_CATEGORY: {
                list = categoryList;
                break;
            }
            case GROUP_TYPE_CITY: {
                list = cityList;
                break;
            }
            case GROUP_TYPE_GUARANTEE: {
                list = guaranteeList;
                break;
            }
            case GROUP_TYPE_SYSTEM_SLIDE: {
                list = systemSlideList;
                break;
            }
            case GROUP_TYPE_ADVERTISEMENT: {
                list = advertisementList;
                break;
            }
            default: {
                list = new LinkedList<>();
                break;
            }
        }
        mutex.unlock();
        return list;
    }

    public static void copySetupFromServer(Response<ResponseBody> response) throws Exception {
        Exception capturedException = null;
        copyMutex.lock();
        RxFileTool.createOrExistsDir(SETUP_FILE_DIR);
        InputStream in = null;
        try {
            in = response.body().byteStream();
            RxFileTool.copyFile(in, new File(SETUP_FILE_PATH));
        } catch (Exception e) {
            capturedException = e;
        } finally {
            try {
                in.close();
            } catch (Exception e) {

            }
        }
        copyMutex.unlock();
        if (capturedException != null) {
            throw capturedException;
        }
    }

    public static void copySetupFromAsset() throws Exception {
        Exception capturedException = null;
        copyMutex.lock();
        if (!RxFileTool.isFileExists(SETUP_FILE_PATH) || checkAppNewInstallOrUpgrade()) {
            makeUpdateSetupIsNeverUpdate();
            RxFileTool.createOrExistsDir(SETUP_FILE_DIR);
            InputStream in = null;
            try {
                in = MyApp.getAppContext().getAssets().open("setup.json");
                RxFileTool.copyFile(in, new File(SETUP_FILE_PATH));
            } catch (Exception e) {
                capturedException = e;
            } finally {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }

        }
        copyMutex.unlock();
        if (capturedException != null) {
            throw capturedException;
        }
    }

    public static String getSetupFileHash() {
        if (RxFileTool.isFileExists(SETUP_FILE_PATH)) {
            return MD5Util.calculateFileMD5(new File(SETUP_FILE_PATH));
        } else {
            return "";
        }
    }

    public static void populateSetupList() {
        copyMutex.lock();
        Setup[] setupArray = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(SETUP_FILE_PATH);
            setupArray = JSON.parseObject(inputStream, Setup[].class);
        } catch (Exception e) {

        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {

            }
        }
        copyMutex.unlock();
        if (setupArray == null || setupArray.length == 0) {
            return;
        }
        mutex.lock();
        setupList.clear();
        for (Setup setup : setupArray) {
            setupList.add(setup);
        }
        courseTypeList.clear();
        courseTypeList.addAll(extractDataByGroupType(GROUP_TYPE_COURSE_TYPE));
        suitablePeopleList.clear();
        suitablePeopleList.addAll(extractDataByGroupType(GROUP_TYPE_SUITABLE_PEOPLE));
        cityList.clear();
        cityList.addAll(extractDataByGroupType(GROUP_TYPE_CITY));
        learnTargetList.clear();
        learnTargetList.addAll(extractDataByGroupType(GROUP_TYPE_LEARN_TARGET));
        categoryList.clear();
        categoryList.addAll(extractDataByGroupType(GROUP_TYPE_CATEGORY));
        guaranteeList.clear();
        guaranteeList.addAll(extractDataByGroupType(GROUP_TYPE_GUARANTEE));
        systemSlideList.clear();
        systemSlideList.addAll(extractDataByGroupType(GROUP_TYPE_SYSTEM_SLIDE));
        advertisementList.clear();
        advertisementList.addAll(extractDataByGroupType(GROUP_TYPE_ADVERTISEMENT));
        mutex.unlock();
    }

    public static void updateSetupNow() {
        UpdateSetupService.updateSetup(MyApp.getAppContext());
    }

    public static void updateSetupWithRandomDelay() {
        Random random = new Random();
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                updateSetupNow();
            }
        }, RANDOM_DELAY_LOW_BOUND_MS + (long) (random.nextFloat() * RANDOM_DELAY_RANGE_MS));
    }

    public static void updateSetupIfTooOld() {
        if (System.currentTimeMillis() - PreferenceUtil.getLong(PREF_KEY_LAST_UPDATE_SETUP_TIMESTAMP, 0) > UPDATE_SETUP_INTERVAL_MS) {
            PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_SETUP_TIMESTAMP, System.currentTimeMillis());
            Timber.e("updateSetupIfTooOld:detect setup too old and will update immediately...");
            updateSetupWithRandomDelay();
        }
    }

    public static void makeUpdateSetupIsNeverUpdate() {
        PreferenceUtil.putLong(PREF_KEY_LAST_UPDATE_SETUP_TIMESTAMP, 0);
    }


    public static boolean checkAppNewInstallOrUpgrade() {
        String prefVersionName = PreferenceUtil.getString(PREF_KEY_VERSION_NAME, "");
        String currentVersionName = AppUtils.getAppVersionName();
        if (TextUtils.isEmpty(currentVersionName)) {
            return true;
        }
        PreferenceUtil.putString(PREF_KEY_VERSION_NAME, currentVersionName);
        return !currentVersionName.equals(prefVersionName);
    }


    public static void installUpdateAlarm() {
        Intent intent = new Intent(MyApp.getAppContext(), UpdateSetupService.class);
        PendingIntent pintent = PendingIntent.getService(MyApp.getAppContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarm = (AlarmManager) MyApp.getAppContext().getSystemService(Context.ALARM_SERVICE);
        if (alarm != null) {
            alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, UPDATE_SETUP_INTERVAL_MS, UPDATE_SETUP_INTERVAL_MS, pintent);
        }
    }

    private static List<Setup> extractDataByGroupType(String groupType) {
        List<Setup> list = new LinkedList<>();
        for (Setup setup : setupList) {
            if (setup.getGroupType().equals(groupType)) {
                list.add(setup);
            }
        }
        return list;
    }

    public static void cacheSetupInfo(SetupInfo setupInfo) {
        setupInfoMutex.lock();
        try {
            PreferenceUtil.putString(PREF_KEY_SETUPINFO, JSON.toJSONString(setupInfo));
            PreferenceUtil.putLong(PREF_KEY_SETUPINFO_TIMESTAMP, System.currentTimeMillis());
        } catch (Exception e) {

        }
        setupInfoMutex.unlock();
    }

    public static SetupInfo getCachedSetupInfo() {
        setupInfoMutex.lock();
        long cacheTimestamp = PreferenceUtil.getLong(PREF_KEY_SETUPINFO_TIMESTAMP, 0);
        if (System.currentTimeMillis() - cacheTimestamp > SETUPINFO_TIMEOUT_MS) {
            setupInfoMutex.unlock();
            return null;
        } else {
            String json = PreferenceUtil.getString(PREF_KEY_SETUPINFO, "");
            SetupInfo setupInfo;
            try {
                setupInfo = JSON.parseObject(json, SetupInfo.class);
            } catch (Exception e) {
                setupInfo = null;
            }
            setupInfoMutex.unlock();
            return setupInfo;
        }
    }

    public static LocationData convertSetupInfoToLocationData(SetupInfo setupInfo) {
        LocationData locationData = new LocationData();
        try {
            locationData.setCountry("中国");
            String[] address = setupInfo.getCity().split(" ");
            locationData.setProvince(address[0].replace("省", ""));
            locationData.setCity(address[1].replace("市", ""));
            locationData.setSuccess(true);
        } catch (Exception e) {

        }
        return locationData;
    }

    public static void flushSetupInfoCache() {
        setupInfoMutex.lock();
        PreferenceUtil.putString(PREF_KEY_SETUPINFO, "");
        PreferenceUtil.putLong(PREF_KEY_SETUPINFO_TIMESTAMP, 0);
        setupInfoMutex.unlock();
    }
}
